import React, { Suspense, useEffect, useMemo } from 'react';
import ReactFlow, { NodeProps, ReactFlowProvider, SelectionMode, useReactFlow } from 'reactflow';
import { useContextSelector } from 'use-context-selector';
import 'reactflow/dist/style.css';

import { UserRoleEnum } from '@/common/app/constants';
import FlowController from '@/components/workflow/FlowController';
import HelperLines from '@/components/workflow/HelperLines';
import useWorkflow from '@/hooks/use-workflow';
import '@/pages/app/detail/styles/module.scss';
import { useOrchestrationStore } from '@/store/orchestrationStore';
import { FlowNodeTypeEnum } from '@/types/workflow/constant';
import { FlowNodeItemType } from '@/types/workflow/node';

import { Spin } from 'antd';

import { WorkflowContext } from '../context';

import ButtonEdge from './ButtonEdge';
import { connectionLineStyle, defaultEdgeOptions } from './constants';
import { NodeSystemConfig } from './nodes';

// 局部loading组件，避免使用顶层的CircleLoading
function LocalLoading() {
  return (
    <div className="flex h-full w-full items-center justify-center">
      <Spin size="default" tip="组件加载中..." />
    </div>
  );
}

const NodeSimple = React.lazy(() => import('./nodes/NodeSimple'));
const NodeNoFolde = React.lazy(() => import('./nodes/NodeNoFolde'));
const NodeWorkflowStart = React.lazy(() => import('./nodes/NodeWorkflowStart'));
const NodeIfElse = React.lazy(() => import('./nodes/NodeIfElse'));
const NodeCode = React.lazy(() => import('./nodes/NodeCode'));
const NodeAnswer = React.lazy(() => import('./nodes/NodeAnswer/NodeAnswer'));
const NodeHttp = React.lazy(() => import('./nodes/NodeHttp'));
const NodeVariableUpdate = React.lazy(
  () => import('./nodes/NodeVariableUpdate/NodeVariableUpdate'),
);
const NodeTools = React.lazy(() => import('./nodes/NodeTools'));
const NodeUserSelect = React.lazy(() => import('./nodes/NodeUserSelect/NodeUserSelect'));
const NodeComment = React.lazy(() => import('./nodes/NodeComment'));
const NodeFormInput = React.lazy(() => import('./nodes/NodeFormInput'));
const NodeDatasetConcat = React.lazy(() => import('./nodes/NodeDatasetConcat'));
const NodeCQNode = React.lazy(() => import('./nodes/NodeCQnode/NodeCQNode'));
const NodePluginConfig = React.lazy(() => import('./nodes/NodePluginIO/NodePluginConfig'));
const NodeExtract = React.lazy(() => import('./nodes/NodeExtract'));
const NodeToolParams = React.lazy(() => import('./nodes/NodeToolParams'));
const NodeLoop = React.lazy(() => import('./nodes/Loop/NodeLoop'));
const NodeLoopStart = React.lazy(() => import('./nodes/Loop/NodeLoopStart'));
const NodeLoopEnd = React.lazy(() => import('./nodes/Loop/NodeLoopEnd'));
const PluginInput = React.lazy(() => import('./nodes/NodePluginIO/PluginInput'));
const PluginOutput = React.lazy(() => import('./nodes/NodePluginIO/PluginOutput'));

// mcp 相关
const NodeMcpToolSet = React.lazy(() => import('./nodes/NodeMcp/NodeToolSet'));
const NodeMcpTool = React.lazy(() => import('./nodes/NodeMcp/NodeTool'));

// 传入一个节点组件，返回带 loading 的节点组件
function withSuspenseLoading<T extends NodeProps>(NodeComponent: React.ComponentType<T>) {
  return (props: T) => (
    <Suspense
      fallback={
        <div className="flex h-full w-full items-center justify-center">
          <Spin size="default" tip="组件加载中..." />
        </div>
      }
    >
      <NodeComponent {...props} />
    </Suspense>
  );
}

// const CustomNode = React.lazy(() => import('./CustomNode'));
export const minZoom = 0.1;
export const maxZoom = 1.5;
// 设置默认节点类型为CustomNode
const nodeTypes = {
  [FlowNodeTypeEnum.emptyNode]: withSuspenseLoading(NodeSimple),
  [FlowNodeTypeEnum.globalVariable]: withSuspenseLoading(NodeSimple),
  [FlowNodeTypeEnum.textEditor]: withSuspenseLoading(NodeSimple),
  [FlowNodeTypeEnum.customFeedback]: withSuspenseLoading(NodeSimple),
  [FlowNodeTypeEnum.systemConfig]: NodeSystemConfig,
  [FlowNodeTypeEnum.pluginConfig]: withSuspenseLoading(NodePluginConfig),
  [FlowNodeTypeEnum.workflowStart]: withSuspenseLoading(NodeWorkflowStart),
  [FlowNodeTypeEnum.chatNode]: withSuspenseLoading(NodeSimple),
  [FlowNodeTypeEnum.readFiles]: withSuspenseLoading(NodeSimple),
  [FlowNodeTypeEnum.datasetSearchNode]: withSuspenseLoading(NodeSimple),
  [FlowNodeTypeEnum.datasetConcatNode]: withSuspenseLoading(NodeDatasetConcat),
  [FlowNodeTypeEnum.answerNode]: withSuspenseLoading(NodeAnswer),
  [FlowNodeTypeEnum.classifyQuestion]: withSuspenseLoading(NodeCQNode),
  [FlowNodeTypeEnum.contentExtract]: withSuspenseLoading(NodeExtract),
  [FlowNodeTypeEnum.httpRequest468]: withSuspenseLoading(NodeHttp),
  [FlowNodeTypeEnum.runApp]: withSuspenseLoading(NodeSimple),
  [FlowNodeTypeEnum.appModule]: withSuspenseLoading(NodeSimple),
  [FlowNodeTypeEnum.pluginInput]: withSuspenseLoading(PluginInput),
  [FlowNodeTypeEnum.pluginOutput]: withSuspenseLoading(PluginOutput),
  [FlowNodeTypeEnum.pluginModule]: withSuspenseLoading(NodeSimple),
  [FlowNodeTypeEnum.queryExtension]: withSuspenseLoading(NodeSimple),
  [FlowNodeTypeEnum.tools]: withSuspenseLoading(NodeTools),
  [FlowNodeTypeEnum.stopTool]: (data: NodeProps<FlowNodeItemType>) => (
    <NodeSimple {...data} minW="100px" maxW="300px" />
  ),
  [FlowNodeTypeEnum.toolParams]: withSuspenseLoading(NodeToolParams),
  // [FlowNodeTypeEnum.lafModule]: CustomNode,
  [FlowNodeTypeEnum.ifElseNode]: withSuspenseLoading(NodeIfElse),
  [FlowNodeTypeEnum.variableUpdate]: withSuspenseLoading(NodeVariableUpdate),
  [FlowNodeTypeEnum.code]: withSuspenseLoading(NodeCode),
  [FlowNodeTypeEnum.userSelect]: withSuspenseLoading(NodeUserSelect),
  [FlowNodeTypeEnum.loop]: withSuspenseLoading(NodeLoop),
  [FlowNodeTypeEnum.loopStart]: withSuspenseLoading(NodeLoopStart),
  [FlowNodeTypeEnum.loopEnd]: withSuspenseLoading(NodeLoopEnd),
  [FlowNodeTypeEnum.formInput]: withSuspenseLoading(NodeFormInput),
  [FlowNodeTypeEnum.comment]: withSuspenseLoading(NodeComment),
  [FlowNodeTypeEnum.getTime]: withSuspenseLoading(NodeNoFolde),
  [FlowNodeTypeEnum.toolSet]: withSuspenseLoading(NodeMcpToolSet),
  [FlowNodeTypeEnum.tool]: withSuspenseLoading(NodeMcpTool),
};

const edgeTypes = {
  default: ButtonEdge,
  flowEdge: ButtonEdge, // 添加flowEdge类型映射
};

function Flow({ preview }: { preview: boolean }) {
  const { nodes, edges, reactFlowWrapper, workflowControlMode } = useContextSelector(
    WorkflowContext,
    (v) => v,
  );

  const { userRole } = useOrchestrationStore();

  const isPreivew = useMemo(() => {
    return preview || userRole !== UserRoleEnum.admin;
  }, [userRole, preview]);

  const { fitView } = useReactFlow();

  const [hasFit, setHasFit] = React.useState(false);

  useEffect(() => {
    if (hasFit) return;
    if (!nodes || nodes.length === 0) return;
    const timer = setTimeout(() => {
      fitView({
        duration: 300,
        padding: 0.8,
      });
      setHasFit(true);
    }, 500);
    return () => clearTimeout(timer);
  }, [nodes, fitView, hasFit]);

  const {
    handleNodesChange,
    handleEdgeChange,
    onConnectStart,
    onConnectEnd,
    customOnConnect,
    onEdgeMouseEnter,
    onEdgeMouseLeave,
    helperLineHorizontal,
    helperLineVertical,
    onNodeDragStop,
    onPaneContextMenu,
    onPaneClick,
  } = useWorkflow();

  const previewModeSettings = {
    nodesDraggable: false,
    nodesConnectable: false,
    elementsSelectable: false,
    edgesUpdatable: false,
  };

  return (
    <div
      ref={reactFlowWrapper}
      className="workflow h-full w-full flex-1 overflow-hidden"
      style={{ position: 'relative' }}
    >
      <ReactFlow
        ref={reactFlowWrapper}
        nodes={nodes}
        edges={edges}
        minZoom={minZoom}
        maxZoom={maxZoom}
        defaultEdgeOptions={defaultEdgeOptions}
        elevateEdgesOnSelect
        connectionLineStyle={connectionLineStyle}
        nodeTypes={nodeTypes}
        edgeTypes={edgeTypes}
        connectionRadius={50}
        proOptions={{ hideAttribution: true }}
        onNodesChange={handleNodesChange}
        onEdgesChange={handleEdgeChange}
        onConnect={customOnConnect}
        onConnectStart={onConnectStart}
        onConnectEnd={onConnectEnd}
        onEdgeMouseEnter={onEdgeMouseEnter}
        onEdgeMouseLeave={onEdgeMouseLeave}
        panOnScrollSpeed={2}
        onPaneContextMenu={onPaneContextMenu}
        onPaneClick={onPaneClick}
        {...(isPreivew ? previewModeSettings : {})}
        {...(workflowControlMode === 'select'
          ? {
              selectionMode: SelectionMode.Full,
              selectNodesOnDrag: false,
              selectionOnDrag: true,
              selectionKeyCode: null,
              panOnDrag: false,
              panOnScroll: true,
            }
          : {})}
        onNodeDragStop={onNodeDragStop}
      >
        <FlowController preview={isPreivew} />
        {/* <NodeFlowSystemConfig /> */}
        <HelperLines horizontal={helperLineHorizontal} vertical={helperLineVertical} />
      </ReactFlow>
    </div>
  );
}

function FlowWithProvider({ preview }: { preview: boolean }) {
  return (
    <ReactFlowProvider>
      <Suspense fallback={<LocalLoading />}>
        <Flow preview={preview} />
      </Suspense>
    </ReactFlowProvider>
  );
}

export default React.memo(FlowWithProvider);
